package com.dpp.dbase.api;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import androidx.annotation.RawRes;

import com.dpp.dbase.callback.MyCallBack;
import com.dpp.dbase.result.PdResult;
import com.esri.arcgisruntime.data.GeoPackage;
import com.esri.arcgisruntime.data.GeoPackageFeatureTable;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.loadable.LoadStatus;
import com.esri.arcgisruntime.symbology.UniqueValueRenderer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Semaphore;

/**
 * 一些数据内容
 */
public class PdParent {

    protected static final Semaphore semaphore = new Semaphore(1); // 允许最多1个线程同时访问

    private static FeatureLayer mFeatureLayer = null, mPointShpLayer = null, mPolylineShpLayer = null, mPolygonShpLayer = null;

    protected String dbLogName = UUID.randomUUID().toString().replace("-", "") + "pddb.txt";
    protected String gpkgLogName = UUID.randomUUID().toString().replace("-", "") + "pdgpkg.txt";

    //是否开启日志记录，默认不开启
    protected static boolean logTarget = false;


    //初始化定义，是否开启日志记录
    public static void init(boolean logRecords) {
        logTarget = logRecords;
    }


    /**
     * 返回总的
     *
     * @return
     */
    protected FeatureLayer getFeatureLayer() {
        return mFeatureLayer != null ? mFeatureLayer : null;
    }

    /**
     * 返回点状
     *
     * @return
     */
    protected FeatureLayer getPointShpLayer() {
        return mPointShpLayer != null ? mPointShpLayer : null;
    }

    /**
     * 返回线状
     *
     * @return
     */
    protected FeatureLayer getPolylineShpLayer() {
        return mPolylineShpLayer != null ? mPolylineShpLayer : null;
    }

    /**
     * 返回面状
     *
     * @return
     */
    protected FeatureLayer getPolygonShpLayer() {
        return mPolygonShpLayer != null ? mPolygonShpLayer : null;
    }

    /**
     * 传入参数加载gpkg数据库，这里只有点线面返回，可以用可以不用，数据库名字也叫point polyline polygon固定
     *
     * @param dbPath
     * @param where
     * @param uniqueValueRenderer
     * @param loadCallBack
     */
    protected void loadGpkg(String dbPath, String where, UniqueValueRenderer uniqueValueRenderer, MyCallBack.loadCallBack loadCallBack) {
        Map<String, FeatureLayer> mapFeatureLayer = new HashMap<>();
        GeoPackage geoPackage = new GeoPackage(dbPath);
        geoPackage.loadAsync();
        geoPackage.addDoneLoadingListener(() -> {
            LoadStatus loadStatus = geoPackage.getLoadStatus();
            if (loadStatus == LoadStatus.LOADED) {
                List<GeoPackageFeatureTable> geoPackageFeatureTables = geoPackage.getGeoPackageFeatureTables();
                if (geoPackageFeatureTables != null) {
                    for (GeoPackageFeatureTable geoPackageFeatureTable : geoPackageFeatureTables) {
                        mFeatureLayer = new FeatureLayer(geoPackageFeatureTable);
                        switch (geoPackageFeatureTable.getTableName()) {
                            case "point": {//点状采样样式
                                if (where != null) {
                                    mFeatureLayer.setDefinitionExpression(where);
                                }
                                mFeatureLayer.setRenderer(uniqueValueRenderer);
                                mPointShpLayer = mFeatureLayer;
                                mPointShpLayer.setVisible(true);
                                mapFeatureLayer.put("mPointShpLayer", mPointShpLayer);
                                break;
                            }
                            case "polyline": {//线状采样样式
                                if (where != null) {
                                    mFeatureLayer.setDefinitionExpression(where);
                                }
                                mFeatureLayer.setRenderer(uniqueValueRenderer);
                                mPolylineShpLayer = mFeatureLayer;
                                mPolylineShpLayer.setVisible(true);
                                mapFeatureLayer.put("mPolylineShpLayer", mPolylineShpLayer);
                                break;
                            }
                            case "polygon": {//面状采样样式
                                if (where != null) {
                                    mFeatureLayer.setDefinitionExpression(where);
                                }
                                mFeatureLayer.setRenderer(uniqueValueRenderer);
                                mPolygonShpLayer = mFeatureLayer;
                                mPolygonShpLayer.setVisible(true);
                                mapFeatureLayer.put("mPolygonShpLayer", mPolygonShpLayer);
                                break;
                            }
                        }
                    }
                    loadCallBack.success(mapFeatureLayer);
                } else {
                    loadCallBack.fail("加载GPKG数据库失败,geoPackageFeatureTables为空");
                }
            } else {
                loadCallBack.fail("加载GPKG数据库失败");
            }
        });
    }


    private SQLiteDatabase dbGpkg;

    /**
     * 加载gpkg的db数据库
     *
     * @param dbPath
     * @param dbName
     * @param dbVersion
     * @param context
     * @param id
     * @return
     */
    protected SQLiteDatabase getSQLiteDatabase(String dbPath, String dbName, int dbVersion, Context context, @RawRes int id) {
        File f = new File(dbPath);
        boolean mkdir = true;
        if (!f.exists()) {
            mkdir = f.mkdir();
            System.out.println(mkdir);
            if (!mkdir) {
                mkdir = f.mkdirs();
            }
        }
        if (mkdir) {
            try {
                File file = new File(dbPath + File.separator + dbName);
                if (!(file.exists())) {
                    file.createNewFile();
                    InputStream is = context.getResources().openRawResource(id); //欲导入的数据库

                    FileOutputStream fos = new FileOutputStream(dbPath + File.separator + dbName);
                    byte[] buffer = new byte[400000];
                    int count = 0;
                    while ((count = is.read(buffer)) > 0) {
                        fos.write(buffer, 0, count);
                    }
                    fos.close();
                    is.close();
                    dbGpkg = SQLiteDatabase.openOrCreateDatabase(dbPath + File.separator + dbName,
                            null);
                    dbGpkg.setVersion(dbVersion);

                    return dbGpkg;
                }
                dbGpkg = SQLiteDatabase.openOrCreateDatabase(dbPath + File.separator + dbName,
                        null);
                updateDatabase(dbGpkg.getVersion(), dbPath, dbName, dbVersion, context, id);
                return dbGpkg;
            } catch (Exception e) {
                return null;
            }
        } else {
            return null;
        }
    }

    private void updateDatabase(int oldVersion, String dbPath, String dbName, int dbVersion, Context context, @RawRes int id) {
        if (oldVersion >= dbVersion) {
            return;
        }
        updateDB(dbPath, dbName, dbVersion, context, id);
        dbGpkg.setVersion(dbVersion);
    }

    private void updateDB(String dbPath, String dbName, int dbVersion, Context context, @RawRes int id) {
        closeDatabase();
        File db = new File(dbPath);
        db.delete();
        getSQLiteDatabase(dbPath, dbName, dbVersion, context, id);
    }

    private void closeDatabase() {
        this.dbGpkg.close();
    }


    /**
     * 备份/还原数据库
     *
     * @param dbPath     当前数据库路径
     * @param backDbPath 需要备份到的数据库路径
     * @return
     */
    protected PdResult backDb(String dbPath, String backDbPath) {
        FileOutputStream fos = null;
        FileInputStream stream = null;
        try {
            File file = new File(backDbPath);
            if (file.exists()) {
                //文件存在，先删除
                boolean delete = file.delete();
                if (!delete) {
                    return PdResult.Fail("数据库备份，文件删除失败");
                }
            }
            File fileOld = new File(dbPath);
            File fileNew = new File(backDbPath);
            if (!fileNew.exists()) {
                fileNew.createNewFile();
            }
            stream = new FileInputStream(fileOld);

            fos = new FileOutputStream(fileNew);
            byte[] buffer = new byte[400000];
            int count = 0;
            while ((count = stream.read(buffer)) > 0) {
                fos.write(buffer, 0, count);
            }
            return PdResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return PdResult.Fail("数据库备份失败：" + e.getMessage());
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (stream != null) {
                    stream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
